package firemanager;

import java.util.ArrayList;

import agents.UtilsAgents;
//import agents.CoordinatorAgent.ReceiveBehaviour;
import building.Cell;
import building.InfoAgent;
import building.InfoGame;

import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.OneShotBehaviour;
import jade.core.behaviours.SimpleBehaviour;
import jade.domain.AMSService;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.FailureException;
import jade.domain.FIPAAgentManagement.NotUnderstoodException;
import jade.domain.FIPAAgentManagement.RefuseException;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.lang.acl.UnreadableException;
import jade.proto.AchieveREResponder;

public class FiremanManager extends Agent {

	/**
	 * The police class that cures all the injured people in case of: -
	 * intentional fire - bank robbery - car accident - rebellion
	 * 
	 * @author Dabiste Sorin
	 */
	private static final long serialVersionUID = 1L;
	private ProtocolContractNetInitiator contractNetInitiator;
	private ArrayList<AID> civilians;
	private InfoGame game;
	private int currFloor = -1;
	// private ServiceDescription searchCriterion;
	private ReceiveFinishLoad receiveFinishLoad;
	private SendFinishDownload finishDownload;

	protected void setup() {
		System.out.println(this.getLocalName() + " is ready.");

		// Register the agent to the DF
		ServiceDescription sd1 = new ServiceDescription();
		sd1.setType(UtilsAgents.FIREMANAGER_AGENT);
		sd1.setName(getLocalName());
		sd1.setOwnership(UtilsAgents.OWNER);
		DFAgentDescription dfd = new DFAgentDescription();
		dfd.addServices(sd1);
		dfd.setName(getAID());
		try {
			DFService.register(this, dfd);
			// showMessage("Registered to the DF");
			System.out.println("Registered to the DF");
		} catch (FIPAException e) {
			System.err.println(getLocalName() + " registration with DF "
					+ "unsucceeded. Reason: " + e.getMessage());
			doDelete();
		}

		// contractNetInitiator = new ProtocolContractNetInitiator();
		// addBehaviour(new EvacuatorBehaviour(this));

		// searchCriterion = new ServiceDescription();
		// searchCriterion.setType(UtilsAgents.CIVILLIAN_AGENT);

		// addBehaviour(new SendToCivilians(this));
		// addBehaviour(new ReceiveBehaviour(this));

		// Add a Behavior to receive Turns
		MessageTemplate mt = MessageTemplate
				.MatchProtocol(agents.UtilsAgents.PROTOCOL_TURN);
		this.addBehaviour(new QueriesReceiver(this, mt));

		MessageTemplate msInf = MessageTemplate
				.MatchProtocol(agents.UtilsAgents.INFORM);
		this.addBehaviour(new HelpResponder(this, msInf));

		receiveFinishLoad = new ReceiveFinishLoad();
		contractNetInitiator = new ProtocolContractNetInitiator();

		/**
		 * Add a behavior to receive that the harvester load successful garbage.
		 */
		receiveFinishLoad.addBehaviour(this);

		/**
		 * Add a behavior to receive that the harvester download all garbage
		 * into recycling center.
		 */
		new ReceiveFinishLoad().addBehaviour(this);

		/**
		 * Add a behavior to relay movement orders from fireman to the
		 * coordinator agent.
		 */
		new MovementRely().addBehavior(this,
				agents.UtilsAgents.COORDINATOR_AGENT);
		// super.setup();

		// super.setup();
	}

	class QueriesReceiver extends AchieveREResponder {

		private InfoGame game;
		private Cell cell;

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * jade.proto.AchieveREResponder#prepareResponse(jade.lang.acl.ACLMessage
		 * )
		 */
		@Override
		protected ACLMessage prepareResponse(ACLMessage arg0)
				throws NotUnderstoodException, RefuseException {
			return null;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * jade.proto.AchieveREResponder#prepareResultNotification(jade.lang
		 * .acl.ACLMessage, jade.lang.acl.ACLMessage)
		 */
		@Override
		protected ACLMessage prepareResultNotification(ACLMessage arg0,
				ACLMessage arg1) throws FailureException {
			return null;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * jade.proto.AchieveREResponder#handleRequest(jade.lang.acl.ACLMessage)
		 */
		@Override
		/*
		 * protected ACLMessage handleRequest(ACLMessage arg0) throws
		 * NotUnderstoodException, RefuseException { try { Object objectReceived
		 * = arg0.getContentObject(); if (objectReceived instanceof InfoGame) {
		 * // Is the coordinator informing of a new turn game = (InfoGame)
		 * objectReceived;
		 * showMessage("New turn received from coordinator: "+game
		 * .getInfo().getTurn());
		 * 
		 * // Find all my agents and send them the new turn ACLMessage message =
		 * new ACLMessage(ACLMessage.REQUEST); for (int r = 0; r <
		 * game.getMap().length; r++) for (int c = 0; c <
		 * game.getMap()[0].length; c++) { System.out.println("cella" + c +"-" +
		 * r); Cell cell = game.getCell(r, c); if (cell != null) if
		 * (cell.isThereAnAgent()) { InfoAgent a = cell.getAgent(); if
		 * (a.getAID().getLocalName().startsWith("C")) {
		 * System.out.println("cell.Agent " + a.getAID().getLocalName());
		 * message.addReceiver(a.getAID()); } } }
		 * message.setSender(this.myAgent.getAID());
		 * message.setContentObject(game);
		 * 
		 * // Send new torn for all harvesters. this.myAgent.send(message);
		 * System.out.println("envio" + cell + game.ncols);
		 * contractNetInitiator.addBehaviour(this.myAgent, cell); }
		 * 
		 * } catch (UnreadableException e) { e.printStackTrace(); //
		 * showMessage("Received an Object that cannot be understood");
		 * System.err .println("Received an Object that cannot be understood");
		 * } catch (Exception e) { e.printStackTrace(); } return
		 * super.handleRequest(arg0); }
		 */
		protected ACLMessage handleRequest(ACLMessage arg0)
				throws NotUnderstoodException, RefuseException {
			try {
				Object objectReceived = arg0.getContentObject();

				if (objectReceived instanceof InfoGame) {
					// Is the coordinator informing of a new turn
					game = (InfoGame) objectReceived;
					System.err.println("GAME IN FiremenManager "
							+ game.toString());
					// showMessage("New turn received from coordinator: "+game.getInfo().getTurn());

					// Find all my agents and send them the new turn
					ACLMessage message = new ACLMessage(ACLMessage.REQUEST);
					// for(int f=0;f<game.getMap().length;f++)
					// Cell temp=
					// agents.UtilsAgents.findAgent(this.myAgent.getAID(),
					// game);
					int countFiremen = 0;
					if (!game.equals(null)) {
						// currFloor=temp.getFloor();
						for (int f = 0; f < game.getMap().nfloor; f++) {
							for (int r = 0; r < game.getMap().length; r++)
								for (int c = 0; c < game.getMap().width; c++) {
									Cell cell = game.getCell(r, c, f);
									if (cell != null)
										if (cell.isThereAnAgent()) {
											InfoAgent a = cell.getAgent();
											if (a.getAgent().equals("F")) {
												message.addReceiver(a.getAID());
												countFiremen++;
												System.out
														.println(this.myAgent
																.getLocalName()
																+ "sending initial request"
																+ a.getAID());
											}
										}
								}
						}
						if (countFiremen == 0) {
							// finishDownload.addBehaviour(this.myAgent);

							System.out.println("no more firemen in my floor"
									+ myAgent.getLocalName());

						} else {

							message.setProtocol(agents.UtilsAgents.PROTOCOL_TURN);
							message.setSender(this.myAgent.getAID());
							message.setContentObject(game);

							// Actualizing game.
							receiveFinishLoad.setGame(game);

							// Send new torn for all harvesters.
							this.myAgent.send(message);

							// For each garbage do ContractNetInitiator
							// for(int f=0;f<game.getMap().length;f++){
							for (int f1 = 0; f1 < game.getMap().nfloor; f1++) {
								for (int r1 = 0; r1 < game.getMap().length; r1++) {
									for (int c1 = 0; c1 < game.getMap().width; c1++) {
										Cell cell1 = game.getCell(r1, c1, f1);
										if (cell1 != null) {
											// If that cell is building.
											if (cell1.getCellType() == Cell.FIRE) {
												// And not is recycling_center.
												/*
												 * if(cell.getCellType()!=Cell.
												 * RECYCLING_CENTER) //if
												 * getGarbageunits is 0 -> no
												 * garbage.
												 * if(cell.getGarbageUnits()>0)
												 * { //Execute ContratNet to
												 * send harvesters that cell
												 * with garbage.
												 * contractNetInitiator
												 * .addBehaviour (this.myAgent,
												 * cell); }
												 */
												contractNetInitiator
														.addBehaviour(
																this.myAgent,
																cell1, game);
											}
										}
									}
								}
							}
						}

					}
				}

			} catch (UnreadableException e) {
				e.printStackTrace();
				showMessage("Received an Object that cannot be understood");
			} catch (Exception e) {
				e.printStackTrace();
			}

			return super.handleRequest(arg0);

		}

		private void showMessage(String string) {
			// TODO Auto-generated method stub
			System.out.println(string);
		}

		/**
		 *
		 */
		private static final long serialVersionUID = -6176920249600913698L;

		public QueriesReceiver(Agent arg0, MessageTemplate arg1) {
			super(arg0, arg1);
		}
	}

	/***** CODE CATERINA ******************************/

	class HelpResponder extends AchieveREResponder {

		public HelpResponder(Agent a, MessageTemplate mt) {
			super(a, mt);
			// TODO Auto-generated constructor stub
		}

		/**
		 *
		 */
		private static final long serialVersionUID = 1L;

		@Override
		protected ACLMessage prepareResponse(ACLMessage arg0)
				throws NotUnderstoodException, RefuseException {
			return null;
		}

		@Override
		protected ACLMessage prepareResultNotification(ACLMessage arg0,
				ACLMessage arg1) throws FailureException {
			return null;
		}

		protected ACLMessage handleRequest(ACLMessage arg0)
				throws NotUnderstoodException, RefuseException {
			try {

				String h = arg0.getContent();
				String convId = arg0.getConversationId();
				AID sender = arg0.getSender();
				ACLMessage risp = new ACLMessage(ACLMessage.INFORM);
				if (convId.equals("1")) {
					System.err.println("H " + h);

					risp.setProtocol(UtilsAgents.INFORM);
					risp.setSender(myAgent.getAID());
					risp.setContent("Allarm received");
					risp.addReceiver(sender);

					showMessage("Evacuator received civilian's ( "
							+ sender.getLocalName() + ")  sos.");
					this.myAgent.send(risp);
				}

			} catch (Exception e) {
				e.printStackTrace();
			}
			return super.handleRequest(arg0);
		}

		private void showMessage(String string) {
			// TODO Auto-generated method stub
			System.out.println(string);
		}

	}

	/**
	 * Coordinator lancia l'allarme all'evacuator evacuator risponde
	 * 
	 * @author Caterina
	 * 
	 */
	class EvacuatorBehaviour extends SimpleBehaviour {

		/**
		 * The behavior class that reports the appropriate message about its
		 * action. - busy - arrested
		 * 
		 * @author Dabiste Sorin
		 */
		private static final long serialVersionUID = 1L;
		private MessageTemplate mt = MessageTemplate
				.MatchPerformative(ACLMessage.INFORM);
		private boolean isDone;

		public EvacuatorBehaviour(Agent agent) {
			super(agent);
		}

		public void action() {
			ACLMessage aclMessage = myAgent.receive(mt);

			if (aclMessage != null) {
				if (aclMessage.getContent().compareTo("Fire Alarm") == 0)
					Report();
				/*
				 * if(aclMessage.getContent().compareTo("Ok") == 0) Report2();
				 */
			}
		}

		private void Report() {
			AID coordinator = new AID("coordinator@" + myAgent.getHap(),
					AID.ISGUID);

			ACLMessage aclMessage = new ACLMessage(ACLMessage.INFORM);

			aclMessage.addReceiver(coordinator);

			aclMessage.setContent("Alarm received");

			myAgent.send(aclMessage);
			isDone = true;
		}

		public boolean done() {
			return isDone;
		}

	}

}